package com.hengpeng.itfin.service.investinfo.impl;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.hengpeng.common.exception.ServiceResult;
import com.hengpeng.common.persist.query.DynamicQuery;
import com.hengpeng.common.util.DateTimeUtil;
import com.hengpeng.common.util.MoneyUtil;
import com.hengpeng.common.util.StringHelper;
import com.hengpeng.itfin.common.SystemConfigUtil;
import com.hengpeng.itfin.service.impl.BaseServiceImpl;
import com.hengpeng.itfin.service.investinfo.InvestInfoService;
import com.hengpeng.itfinbase.constants.RespCodeConstants;
import com.hengpeng.itfinbase.constants.SystemConfigConstants;
import com.hengpeng.itfinbase.constants.TransCodeConstants;
import com.hengpeng.itfinbase.en.ActivityType;
import com.hengpeng.itfinbase.en.BorrowStatus;
import com.hengpeng.itfinbase.en.InvestStatus;
import com.hengpeng.itfinbase.en.RewardRedPacketStatus;
import com.hengpeng.itfinbase.en.TradeMode;
import com.hengpeng.itfinbase.en.TransType;
import com.hengpeng.itfinbase.idAssign.ID;
import com.hengpeng.itfinbase.message.ResponseMessage;
import com.hengpeng.itfinbase.message.activity.InvestBackRebateRequest;
import com.hengpeng.itfinbase.message.activity.InvestRedPacketRequest;
import com.hengpeng.itfinbase.message.partner.InvestInfoRequestMsg;
import com.hengpeng.itfinbase.message.partner.InvestInfoResponseMsg;
import com.hengpeng.itfinbase.message.partner.PartnerTransType;
import com.hengpeng.itfinbase.message.partner.QueryTransStatRequest;
import com.hengpeng.itfinbase.message.partner.QueryTransStatResponse;
import com.hengpeng.itfinbase.message.partner.UsrUnFreezeRequest;
import com.hengpeng.itfinbase.persist.BorrowInfo;
import com.hengpeng.itfinbase.persist.InvestInfo;
import com.hengpeng.itfinbase.persist.MessageTemplates;
import com.hengpeng.itfinbase.persist.SystemLog.LogType;

@Service
@Lazy
public class InvestInfoServiceImpl extends BaseServiceImpl implements InvestInfoService {

    @Override
    public InvestInfo getInvestByUnFreeOrderId(String unFreeOrderId, boolean isLock) {
        DynamicQuery query = new DynamicQuery(InvestInfo.class);
        query.eq("unFreeOderId", unFreeOrderId);
        InvestInfo investInfo = serviceFactory.getPersistService().getByDynamicQuery(InvestInfo.class, query);
        if (isLock && investInfo != null) {
            investInfo = serviceFactory.getPersistService().lockObject(InvestInfo.class, investInfo.getId());
        }
        return investInfo;
    }

    /**
     * <pre>
     *  投资接口调用成功后操作：
     *                        1,更新投资信息状态 
     *                        2,冻结投资人资金信息表中相关资金。 
     *                        3,添加资金流水表相关资金冻结流水。
     *                        4,判断投标总金额是否已经达到募集金额，如果达到募集金额则设置标的状态为：募集结束
     *  投资接口调用失败后操作：
     *                        1,释放投资额度,更新标的信息表中的已募集金额,已募集人数。 
     *                        2,更新投标信息状态为：失败
     * </pre>
     */
    @Override
    public ServiceResult<String> dealInvestResult(InvestInfoResponseMsg response) {
        ServiceResult<String> result = new ServiceResult<String>();
        if (response == null) {
            serviceFactory.getSystemLogService().addLog("", "", LogType.SYSTEMERROR, "汇付通知结果异常,返回结果为null");
        } else if (!RespCodeConstants.CommonCode.TRANS_SUC.equals(response.getRespCode())) {
            result.setIsSuccess(false);
            // 失败
            InvestInfo investInfo = serviceFactory.getDaoFactory().getInvestInfoDao()
                    .get(Long.parseLong(response.getOrdId()));
            if (investInfo == null) {
                serviceFactory.getSystemLogService().addLog(
                        "",
                        response.getOrdId(),
                        LogType.SYSTEMERROR,
                        "投标失败，释放标的额度失败：原投标订单缺失,汇付返回订单号：["
                                + (StringHelper.isEmpty(response.getOrdId()) ? "" : response.getOrdId()) + "]");

            } else if (investInfo.getStatus().equals(InvestStatus.INVESTING)) {
                int i = serviceFactory.getInvestInfoService().updateStatus(investInfo.getId(), InvestStatus.INVESTING,
                        InvestStatus.FAILURE);
                if (i > 0) {
                    /**
                     * 回退红包状态
                     */
                    if (investInfo.getRedPacketId() != null) {
                        serviceFactory.getRedPacketService().updateStatus(investInfo.getRedPacketId(), 
                                RewardRedPacketStatus.USEED, RewardRedPacketStatus.CANUSE, new Date());
                    }
                    BorrowInfo borrowInfo = serviceFactory.getDaoFactory().getBorrowInfoDao()
                            .get(investInfo.getBorrowInfoId());
                    if (borrowInfo != null) {// 释放额度
                        if (borrowInfo.getStatus().equals(BorrowStatus.RAISE)) {
                            int m = serviceFactory.getBorrowService().releaseBorrowMoney(borrowInfo.getId(),
                                    borrowInfo.getRaiseMoney() - investInfo.getInvestMoney(),
                                    borrowInfo.getRaiseNum() - 1);

                            serviceFactory.getSystemLogService().addLog(borrowInfo.getId().toString(),
                                    investInfo.getId().toString(), LogType.INVEST_DO, "释放标的额度成功,标的状态：RAISE,操作结果:" + m);
                        } else if (borrowInfo.getStatus().equals(BorrowStatus.END)) {
                            int n = serviceFactory.getBorrowService().releaseBorrowMoneyStatus(borrowInfo.getId(),
                                    borrowInfo.getRaiseMoney() - investInfo.getInvestMoney(),
                                    borrowInfo.getRaiseNum() - 1, BorrowStatus.RAISE);

                            serviceFactory.getSystemLogService().addLog(borrowInfo.getId().toString(),
                                    investInfo.getId().toString(), LogType.INVEST_DO, "释放标的额度成功,标的状态：END,操作结果:" + n);
                        } else {
                            serviceFactory.getSystemLogService().addLog(
                                    borrowInfo.getId().toString(),
                                    investInfo.getId().toString(),
                                    LogType.INVEST_EXCEPTION,
                                    "释放标的额度失败：原标的信息状态异常或募集金额异常，当前标的状态：" + borrowInfo.getStatus() + "，当前募集金额："
                                            + borrowInfo.getRaiseMoney() + "，借款金额：" + borrowInfo.getBorrowMoney());
                        }
                    } else {
                        serviceFactory.getSystemLogService().addLog(investInfo.getBorrowInfoId().toString(),
                                investInfo.getId().toString(), LogType.INVEST_EXCEPTION, "释放标的额度失败：原借款标的信息缺失");

                        result.setMessage(RespCodeConstants.BorrowInfoCode.BORROWINFO_UNKONW_MSG);
                        result.setCode(RespCodeConstants.BorrowInfoCode.BORROWINFO_UNKONW);
                    }
                } else {
                    serviceFactory.getSystemLogService().addLog(investInfo.getBorrowInfoId().toString(),
                            investInfo.getId().toString(), LogType.INVEST_EXCEPTION, "投标失败释放额度失败,数据库更新投标状态失败");
                }
                // 站内信 投资
                Map<String, Object> map = new HashMap<String, Object>();
                map.put("date", new Date());
                map.put("money", MoneyUtil.convertFenToYuan(investInfo.getInvestMoney()));
                serviceFactory.getMessageService().asynsendSystemMessageByTypeWithUsrCustId(
                        investInfo.getInvestUserTrustAccountId(), MessageTemplates.BusiType.M411.name(), map);
            } else if (investInfo.getStatus().equals(InvestStatus.SUCESS)) {
                /**
                 * 汇付异常通知,第一次通知成功,第二次通知订单失败
                 */
                serviceFactory.getSystemLogService().addLog(investInfo.getBorrowInfoId().toString(),
                        investInfo.getId().toString(), LogType.INVEST_EXCEPTION, "汇付异常通知,第一次通知成功,第二次通知订单失败");
            } else {
                serviceFactory.getSystemLogService().addLog(investInfo.getBorrowInfoId().toString(),
                        investInfo.getId().toString(), LogType.INVEST_MESSAGE,
                        "投标失败已处理,或原投标信息状态异常，当前标的状态[" + investInfo.getStatus() + "]");
            }
            result.setMessage(RespCodeConstants.CommonCode.TRANS_FAIL);
            result.setCode(RespCodeConstants.CommonCode.TRANS_FAIL_MSG);
            return result;
        } else if (RespCodeConstants.CommonCode.TRANS_SUC.equals(response.getRespCode())) {
            // 成功
            InvestInfo investInfo = serviceFactory.getDaoFactory().getInvestInfoDao()
                    .get(Long.parseLong(response.getOrdId()));
            if (investInfo == null) {
                serviceFactory.getSystemLogService().addLog(
                        "",
                        response.getOrdId(),
                        LogType.SYSTEMERROR,
                        "投标成功，开始处理成功结果异常：原投标订单缺失,汇付返回订单号：["
                                + (StringHelper.isEmpty(response.getOrdId()) ? "" : response.getOrdId()) + "]");

            } else if (investInfo.getStatus().equals(InvestStatus.INVESTING)) {
                int i = serviceFactory.getInvestInfoService().updateStatusAndFreeId(investInfo.getId(),
                        response.getFreezeTrxId(), InvestStatus.INVESTING, InvestStatus.SUCESS);
                if (i > 0) {
                    investInfo.setFreezeTrxId(response.getFreezeTrxId());// 设置冻结标识
                    investInfo.setStatus(InvestStatus.SUCESS);
                    BorrowInfo borrowInfo = serviceFactory.getDaoFactory().getBorrowInfoDao()
                            .get(investInfo.getBorrowInfoId());
                    /**
                     * 满标设置筹款结束
                     */
                    if (borrowInfo.getRaiseMoney().longValue() == borrowInfo.getBorrowMoney().longValue()) {
                        borrowInfo.setStatus(BorrowStatus.END);
                        serviceFactory.getPersistService().update(borrowInfo);
                    } else if ((borrowInfo.getBorrowMoney() - borrowInfo.getRaiseMoney()) < borrowInfo.getMinInvest()) {
                        // 标的最后剩余不满足最低投资额的处理
                        borrowInfo.setMinInvest(borrowInfo.getBorrowMoney() - borrowInfo.getRaiseMoney());
                        serviceFactory.getPersistService().update(borrowInfo);
                    }
                    /**
                     * 更新投资人资金信息,添加资金流水
                     */
                    serviceFactory.getAccountService().changeAccountMoney(investInfo.getInvestUserId(),
                            investInfo.getInvestMoney(), 0l, 0l, 0l, TransType.INVEST, TradeMode.FREEZE,
                            investInfo.getId().toString(), "投标成功");
                    /**
                     * 投标成功调用活动接口，投资送等额红包
                     */
                    InvestRedPacketRequest investRedPacketRequest = new InvestRedPacketRequest();
                    investRedPacketRequest.setInvestInfoId(investInfo.getId().toString());
                    investRedPacketRequest.setUserId(investInfo.getInvestUserId());
                    investRedPacketRequest.setUserName(investInfo.getInvestUserName());
                    investRedPacketRequest.setActivityType(ActivityType.INVEST_REDPACKET);
                    investRedPacketRequest.setRewardVal(investInfo.getInvestMoney());
                    investRedPacketRequest.setTransType(TransCodeConstants.ActivityTransCode.INVEST_SEND_REDPACKET);
                    serviceFactory.getPortActiveFactory().remoteTrans(investRedPacketRequest);
                    /**
                     * 根据不同人的角色进行返利 投标成功调用活动接口,投资返利
                     */
                    InvestBackRebateRequest investBackRebateRequest = new InvestBackRebateRequest();
                    investBackRebateRequest.setDurType(borrowInfo.getDurType());
                    investBackRebateRequest.setBorrowDuration(borrowInfo.getBorrowDuration());
                    investBackRebateRequest.setUserId(investInfo.getInvestUserId());
                    investBackRebateRequest.setInvestMoney(investInfo.getInvestMoney());
                    investBackRebateRequest.setInvestInfoId(investInfo.getId());
                    investBackRebateRequest.setTransType(TransCodeConstants.ActivityTransCode.INVEST_SEND_REBATE);
                    investBackRebateRequest.setActivityType(ActivityType.INVEST_REBATE);
                    serviceFactory.getPortActiveFactory().remoteTrans(investBackRebateRequest);
                    /**
                     * <pre>
                     * 投资成功进行红包划账处理：
                     *  2,生成红包使用日志 
                     *  3,调用转账接口转账
                     * </pre>
                     */
                    if (investInfo.getRedPacketId() != null) {
                        serviceFactory.getRedPacketService()
                                .investRedPacketTransfer(investInfo.getRedPacketId(),investInfo);
                    }
                    /**
                     * 调用会员等级升级接口进行会员等级升级,暂不放开
                     */
                    // UserLevelUpRequest userLevelUpRequest = new
                    // UserLevelUpRequest();
                    // userLevelUpRequest.setInvestMoney(investInfo.getInvestMoney());
                    // serviceFactory.getUserInfoService().userLevelUp(userLevelUpRequest);

                    // 站内信 投资
                    Map<String, Object> map = new HashMap<String, Object>();
                    map.put("date", new Date());
                    map.put("money", MoneyUtil.convertFenToYuan(investInfo.getInvestMoney()));
                    serviceFactory.getMessageService().asynsendSystemMessageByTypeWithUsrCustId(
                            investInfo.getInvestUserTrustAccountId(), MessageTemplates.BusiType.M410.name(), map);
                } else {
                    serviceFactory.getSystemLogService().addLog(investInfo.getBorrowInfoId().toString(),
                            investInfo.getId().toString(), LogType.INVEST_MESSAGE, "投标成功更新原投标状态失败,数据库更新状态失败,或状态已被更新");
                }
            } else if (investInfo.getStatus() == InvestStatus.FAILURE) {
                /**
                 * 汇付超时响应或异常通知：第一次通知失败，第二次通知成功：用户退款处理
                 */
                UsrUnFreezeRequest usrUnFreezeRequest = new UsrUnFreezeRequest();
                String unFreeOrderId = ID.getInstanse().getID(18).toString();
                usrUnFreezeRequest.setOrdId(unFreeOrderId);
                usrUnFreezeRequest.setOrdDate(DateTimeUtil.formatToStr(investInfo.getCreateTime(),
                        DateTimeUtil.DATE_FORMAT_YYYYMMDD));
                usrUnFreezeRequest.setTrxId(response.getFreezeTrxId());
                usrUnFreezeRequest.setPartnerTransType(PartnerTransType.UsrUnFreeze);
                usrUnFreezeRequest.setBgRetUrl(service_notify_url);
                usrUnFreezeRequest.setRetUrl(page_return_url);
                serviceFactory.getPartnerService().request(usrUnFreezeRequest);

                serviceFactory.getSystemLogService().addLog(investInfo.getBorrowInfoId().toString(),
                        investInfo.getId().toString(), LogType.INVEST_EXCEPTION, "汇付超时响应或异常通知：第一次通知失败，第二次通知成功：用户退款处理");

            } else {
                serviceFactory.getSystemLogService().addLog(investInfo.getBorrowInfoId().toString(),
                        investInfo.getId().toString(), LogType.INVEST_MESSAGE,
                        "投标成功已处理,或原投标信息状态异常，当前标的状态[" + investInfo.getStatus() + "]");
            }
            result.setIsSuccess(true);
            result.setMessage(RespCodeConstants.CommonCode.TRANS_SUC_MSG);
            result.setCode(RespCodeConstants.CommonCode.TRANS_SUC);
        }
        return result;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public int updateStatusAndFreeId(Long id, String freeOrderId, InvestStatus oldStatus, InvestStatus newStatus) {
        return serviceFactory.getDaoFactory().getInvestInfoDao()
                .updateStatusAndFreeId(id, freeOrderId, oldStatus, newStatus);
    }

    @Override
    public void investQuery() {
        List<InvestInfo> list = serviceFactory.getDaoFactory().getInvestInfoDao()
                .queryList(null, new InvestStatus[] { InvestStatus.INVESTING });
        if (list != null && list.size() > 0) {
            // PoolServer poolServer = new PoolServer(50);
            for (final InvestInfo iv : list) {
                // poolServer.executeTask(new Runnable() {
                // public void run() {
                serviceFactory.getInvestInfoService().doInvestQuery(iv);
                // }
                // });
            }
            // poolServer.endServer();
        }
    }

    @Override
    public void doInvestQuery(InvestInfo investInfo) {
        Date time = DateTimeUtil.addSecond(investInfo.getCreateTime(),
                Long.parseLong(SystemConfigUtil.getConfigValue(SystemConfigConstants.INVEST_LIMIT_TIME)));
        if (time.getTime() < System.currentTimeMillis()) {
            /**
             * <pre>
             * 当投资人投标时,超过指定时间还未完成支付,则系统进行交易状态查询,
             * 查询结果若为交易失败,则进行释放融资额度操作
             * 查询结果若为交易成功,则进行交易信息的补充成功操作.
             * </pre>
             */
            QueryTransStatRequest request = new QueryTransStatRequest();
            request.setOrdId(investInfo.getFreeOderId());
            request.setOrdDate(DateTimeUtil.formatToStr(investInfo.getCreateTime(), DateTimeUtil.DATE_FORMAT_YYYYMMDD));
            request.setPartnerTransType(PartnerTransType.QueryTransStat);
            request.setQueryTransType("FREEZE");
            QueryTransStatResponse response = (QueryTransStatResponse) serviceFactory.getPartnerService().request(
                    request);
            final InvestInfoResponseMsg investResponse = new InvestInfoResponseMsg();
            investResponse.setOrdId(investInfo.getId().toString());
            if (RespCodeConstants.ChinaPnrCode.QUERYDATA_NOT_FOUND.equals(response.getRespCode())
                    || "F".equals(response.getTransStat()) || "U".equals(response.getTransStat())) {
                if (RespCodeConstants.ChinaPnrCode.QUERYDATA_NOT_FOUND.equals(response.getRespCode())) {// 未查到数据
                    investResponse.setRespCode(RespCodeConstants.CommonCode.TRANS_FAIL);
                    investResponse.setRespDesc(RespCodeConstants.CommonCode.TRANS_FAIL_MSG);
                } else if ("F".equals(response.getTransStat())) {// 成功冻结
                    investResponse.setRespCode(RespCodeConstants.CommonCode.TRANS_SUC);
                    investResponse.setRespDesc(RespCodeConstants.CommonCode.TRANS_SUC_MSG);
                    investResponse.setFreezeTrxId(response.getTrxId());
                } else if ("U".equals(response.getTransStat())) {// 未冻结
                    investResponse.setRespCode(RespCodeConstants.CommonCode.TRANS_FAIL);
                    investResponse.setRespDesc(RespCodeConstants.CommonCode.TRANS_FAIL_MSG);
                }
                ServiceResult<String> resulst = serviceFactory.getInvestInfoService().dealInvestResult(investResponse);
                logger.info("投标状态查询定时作业：投标id:" + investResponse.getOrdId() + ",响应消息:" + resulst.getMessage() + ",响应码:"
                        + resulst.getCode() + "");

            }

        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public int updateRaiseMoney(Long id, Long money) {
        return serviceFactory.getDaoFactory().getBorrowInfoDao().updateRaiseMoney(id, money);
    }

    @Override
    public ResponseMessage packInvestRequest(InvestInfoRequestMsg reqMsg) {
        ResponseMessage response = new ResponseMessage();
        /**
         * 借款前先占据借款额度
         */
        BorrowInfo borrowInfo = serviceFactory.getDaoFactory().getBorrowInfoDao()
                .getBorrowInfo(Long.parseLong(reqMsg.getBorrowInfoId()), BorrowStatus.RAISE);
        int i = serviceFactory.getInvestInfoService().updateRaiseMoney(borrowInfo.getId(),
                Long.parseLong(reqMsg.getTransAmt()));
        if (i > 0) {
            /**
             * 生成并保存投资信息
             */
            InvestInfo investInfo = new InvestInfo();
            investInfo.setInvestUserName(reqMsg.getInvestUserName());
            investInfo.setInvestUserId(Long.parseLong(reqMsg.getInvestUserId()));
            investInfo.setInvestUserTrustAccountId(reqMsg.getUsrCustId());
            investInfo.setNowOwnUserId(Long.parseLong(reqMsg.getInvestUserId()));
            investInfo.setNowOwnUserTrustAccountId(reqMsg.getUsrCustId());
            investInfo.setNowOwnUserName(reqMsg.getInvestUserName());
            investInfo.setBorrowInfoId(Long.parseLong(reqMsg.getBorrowInfoId()));
            investInfo.setBorrowName(reqMsg.getBorrowName());
            investInfo.setInvestMoney(Long.parseLong(reqMsg.getTransAmt()));
            investInfo.setRedPacketId(reqMsg.getRedPacketId());
            investInfo.setInvestTime(new Date());
            investInfo.setStatus(InvestStatus.INVESTING);
            investInfo.setCreateTime(new Date());
            investInfo.setUpdateTime(new Date());
            String freeOderId = ID.getInstanse().getID(18).toString();
            investInfo.setFreeOderId(freeOderId);
            investInfo = serviceFactory.getPersistService().save(investInfo);
            reqMsg.setInvestInfoId(investInfo.getId());
            reqMsg.setOrdDate(DateTimeUtil.formatToStr(new Date(), DateTimeUtil.DATE_FORMAT_YYYYMMDD));
            reqMsg.setFreezeOrdId(freeOderId);
        } else {
            response.setRespCode(RespCodeConstants.CommonCode.TRANS_FAIL);
            response.setRespDesc("借款额度已满");
        }
        return response;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public int updateAllInvestInfoStatus(Long borrowInfoId, InvestStatus oldStatus, InvestStatus newStatus) {
        return serviceFactory.getDaoFactory().getInvestInfoDao().updateAllStatus(borrowInfoId, oldStatus, newStatus);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public int updateStatus(Long investInfoId, InvestStatus oldStatus, InvestStatus newStatus) {
        return serviceFactory.getDaoFactory().getInvestInfoDao().updateStatus(investInfoId, oldStatus, newStatus);
    }

}
